package cn.edu.bit.snake;

import java.awt.*;
import java.awt.event.*;
import java.util.*;

public class Snake {	
	public static final int X_MOVEMENT = 15;
	public static final int Y_MOVEMENT = 15;
	public static final int NUM_TO_PASS = 5;
	
	public static int SNAKE_SCORE = 0;
	public static int SNAKE_EAT_FRUIT_NUM = 0;
	
	private int x,y;
	enum Direction {U,L,D,R,S};
	private Direction dir = Direction.R;
	boolean pU = false, pL = false, pD = false, pR = false; //when left key pressed,true it
	private boolean isLive = false;
	private SnakeClient sc = null;
	private int snakeLength;
	
	ArrayList<SnakeLength> sl = new ArrayList<SnakeLength>();
	
	public int getSnakeLength() {
		return snakeLength;
	}
	public void setSnakeLength(int snakeLength) {
		this.snakeLength = snakeLength;
	}
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}
	public Direction getDir() {
		return dir;
	}
	public void setDir(Direction dir) {
		this.dir = dir;
	}
	public boolean isLive() {
		return isLive;
	}
	public void setLive(boolean isLive) {
		this.isLive = isLive;
	}
	
	public Snake(int x, int y, Direction dir, boolean isLive,int snakeLength){
		this.x = x;
		this.y = y;
		this.dir = dir;
		this.isLive = isLive;
		this.snakeLength = snakeLength;
		for (int i = 0;i < snakeLength;i++){
			sl.add(new SnakeLength(x - i * sc.SNAKE_WIDTH,y));
		}
	}
	
	public Snake(int x, int y, Direction dir, boolean isLive,int snakeLength,SnakeClient sc){
		this(x,y,dir,isLive,snakeLength);
		this.sc = sc;
	}
	
	class SnakeLength{
		private int x, y;
		
		public SnakeLength(int x, int y){
			this.x = x;
			this.y = y;
		}

		public int getX() {
			return x;
		}
		public void setX(int x) {
			this.x = x;
		}
		public int getY() {
			return y;
		}
		public void setY(int y) {
			this.y = y;
		}
	}
	
	
	public void draw(Graphics g){
		Color c = g.getColor();
		g.setColor(Color.BLACK);
		g.drawString("Press Space Button to open the menu", 10, 50);
		g.drawString("Your score:" + SNAKE_SCORE, 10, 65);
		g.setColor(Color.RED);

		if (dir != Direction.S)
			move(dir);
		for (int i = 0;i < snakeLength;i++){
			g.fillRect(sl.get(i).x, sl.get(i).y, sc.SNAKE_WIDTH, sc.SNAKE_HEIGHT);
		}
		eatFruit();
		if (judgeCollides())
			dir = Direction.S;
		g.setColor(c);
				
	}
	
	
	public void move(Direction dir){
		switch(dir){
		case D:
			this.setY(this.getY() + this.Y_MOVEMENT);
			break;
		case L:
			this.setX(this.getX() - this.X_MOVEMENT);
			break;
		case R:
			this.setX(this.getX() + this.X_MOVEMENT);
			break;
		case U:
			this.setY(this.getY() - this.Y_MOVEMENT);
			break;
		case S:
			break;
		}

		
		//make every rec move
		for (int i = snakeLength - 1;i > 0;i--){
			sl.get(i).x = sl.get(i - 1).x;
			sl.get(i).y = sl.get(i - 1).y; 
		}
		sl.get(0).x = this.getX();
		sl.get(0).y = this.getY();
	}
	
	public void switchDir(int key){
		Direction oldDir = dir;
		
		switch(key){
		case KeyEvent.VK_UP:
			dir = Direction.U;
			break;
		case KeyEvent.VK_DOWN:
			dir = Direction.D;
			break;
		case KeyEvent.VK_LEFT:
			dir = Direction.L;
			break;
		case KeyEvent.VK_RIGHT:
			dir = Direction.R;
			break;
		}
		
		boolean isBack = preventMoveBack(oldDir,dir);
		if (isBack){
			dir = oldDir;
		}
	}
	
	public void keyPressed(KeyEvent e){
		if (dir == Direction.S)
			return;
		
		int key = e.getKeyCode();
		switchDir(key);
	}
	
	public boolean preventMoveBack(Direction oldDir,Direction dir){
		if (oldDir == Direction.L && dir == Direction.R){
			return true;
		}else if (oldDir == Direction.R && dir == Direction.L){
			return true;
		}else if (oldDir == Direction.U && dir == Direction.D){
			return true;
		}else if (oldDir == Direction.D && dir == Direction.U){
			return true;
		}
		return false;
	}
	
	public Rectangle getRectangle(SnakeLength ssl){
		return new Rectangle(ssl.getX(), ssl.getY(), sc.SNAKE_WIDTH, sc.SNAKE_HEIGHT);
	}
	
	public void eatFruit(){
		Rectangle fruitRec = sc.f.getRectangle(sc.f);
		Rectangle snakeRec = this.getRectangle(this.sl.get(0));
		
		if (fruitRec.intersects(snakeRec)){
			sc.f = null;
			sc.generateFruit();
			int x = sl.get(sl.size() - 1).x;
			int y = sl.get(sl.size() - 1).y;
			this.sl.add(new SnakeLength(x,y));
			this.setSnakeLength(this.getSnakeLength() + 1);
			SNAKE_SCORE += SnakeClient.GAME_LEVEL * 10;
			if (++SNAKE_EAT_FRUIT_NUM == NUM_TO_PASS){
				SNAKE_EAT_FRUIT_NUM = 0;
				SnakeClient.GAME_LEVEL++;
			}
		}
	}
	
	public boolean judgeCollide(Rectangle r1,Rectangle r2){
		if (r1.intersects(r2)){
			return true;
		}
		return false;
	}
	
	public boolean judgeCollides(){
		Rectangle r1 = this.getRectangle(sl.get(0));
		Rectangle r2;
		
		if (sl.get(0).x < 0 || sl.get(0).y < 30 || sl.get(0).x > sc.GAME_WIDTH - sc.SNAKE_WIDTH || sl.get(0).y > sc.GAME_HEIGHT - sc.SNAKE_HEIGHT){
			return true;
		}
		for (int i = 1;i < sl.size();i++){
			r2 = this.getRectangle(sl.get(i));
			Rectangle r3 = r1.intersection(r2);
			if (r3.width <= 0 || r3.height <= 0){
				continue;
			}
			return true;
		}
		return false;
	}

}
